package uk.co.q3c.deplan.server.unit.domain.task;

import org.testng.Assert;
import org.testng.annotations.Test;

import uk.co.q3c.deplan.client.domain.dag.ChangeInvalidException;
import uk.co.q3c.deplan.client.domain.dag.CycleDetectedException;
import uk.co.q3c.deplan.client.domain.dag.Hierarchy;
import uk.co.q3c.deplan.client.domain.dag.SharedStructureChangeLog;
import uk.co.q3c.deplan.client.domain.dag.Vertex;
import uk.co.q3c.deplan.server.unit.dao.LocalDatastoreTestCase;

import com.googlecode.objectify.Key;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;

@Test
public class Hierarchy_UT extends LocalDatastoreTestCase {

	Hierarchy<String> hierarchy;

	@Override
	protected void beforeMethod() throws Exception {
		super.beforeMethod();
		hierarchy = new Hierarchy<String>();
		SharedStructureChangeLog changeLog = new SharedStructureChangeLog();
		hierarchy.setChangeLog(changeLog);
		hierarchy.addVertex("a");
		hierarchy.addVertex("b");
		hierarchy.addVertex("c");
		hierarchy.addVertex("d");
		hierarchy.setName("squiggly");
		hierarchy.setVersion(23);
	}

	/**
	 * Do the lists (parents / children) come back in the same order as it was saved - important for sub tasks. Success relies on the vertex
	 * list and map being serialised. (No reason for them not to be)
	 * 
	 * @throws ChangeInvalidException
	 * @throws CycleDetectedException
	 */
	public void persistedOrder() throws CycleDetectedException, ChangeInvalidException {
		hierarchy.addEdge("a", "d");
		hierarchy.addEdge("a", "b");
		hierarchy.addEdge("a", "c");
		Vertex<String> v = hierarchy.getVertex("a");
		Assert.assertEquals(v.getChildren()
				.get(0)
				.getKey(), "d");
		Assert.assertEquals(v.getChildren()
				.get(1)
				.getKey(), "b");
		Assert.assertEquals(v.getChildren()
				.get(2)
				.getKey(), "c");
		Objectify ofy = ObjectifyService.begin();
		ofy.put(hierarchy);

		Key<Hierarchy<String>> key = ofy.getFactory()
				.getKey(hierarchy);
		Hierarchy<String> h2 = ofy.get(key);

		v = h2.getVertex("a");
		Assert.assertEquals(v.getChildren()
				.get(0)
				.getKey(), "d");
		Assert.assertEquals(v.getChildren()
				.get(1)
				.getKey(), "b");
		Assert.assertEquals(v.getChildren()
				.get(2)
				.getKey(), "c");

	}

	/**
	 * Hierarchy requires that any node only has a single parent node
	 * 
	 * @throws ChangeInvalidException
	 * @throws CycleDetectedException
	 */
	public void singleParent() throws CycleDetectedException, ChangeInvalidException {
		Vertex<String> va = hierarchy.getVertex("a");
		hierarchy.addEdge("a", "d");
		hierarchy.addEdge("a", "b");
		hierarchy.addEdge("a", "c");
		// confirm 'a' has three children
		Assert.assertEquals(va.childCount(), 3);
		// now change parent of c from a to b
		hierarchy.setParentKeyFor("c", "b");
		// 'a' should now have only 2 children
		Assert.assertEquals(va.childCount(), 2);
		// 'c' should have a parent 'b'
		Assert.assertEquals(hierarchy.parentKeyFor("c"), "b");

	}
}
